<?php
/**
 * Created by PhpStorm.
 * User: simon
 * Date: 2016/11/20
 * Time: 10:00
 */

namespace App\Weixin;


use App\Common\WeixinTokenCacher;
use App\Models\WeixinToken;
use Illuminate\Support\Facades\Log;
use p5\objects\TimeUtils;

class WechatServiceClient extends WechatClient
{
    protected $component_appid = "";
    protected $component_appsecret = "";

    public function getAuthLink()
    {
        $appId = $this->component_appid;
        $preAuthCode = $this->getPreAuthCode();
        $root = env("API_SITE_ROOT", "http://api.lintong100.com/index.php/");
        $redirect = $root . "open/grant";
        return "https://mp.weixin.qq.com/cgi-bin/componentloginpage?component_appid=$appId&pre_auth_code=$preAuthCode&redirect_uri=$redirect";
    }

    /**
     * 接收并保存微信推送过来的 component_verify_ticket
     * 在公众号第三方平台创建审核通过后，微信服务器会向其“授权事件接收URL”每隔10分钟定时推送 component_verify_ticket。
     * 第三方平台方在收到ticket推送后也需进行解密（详细请见【消息加解密接入指引】），接收到后必须直接返回字符串success。
     * @return bool
     */
    public function receiveComponentVerifyTicket()
    {
        $this->parseContent();
        $verifyCode = $this->getRevParam("ComponentVerifyTicket");
        if (empty($verifyCode)) {
            return false;
        }
        $token = new WeixinToken();
        $token->set_parameter_name(WechatClient::COMPONENT_VERIFY_TICKET);
        $token->set_parameter_value($verifyCode);
        $token->set_expired_at(TimeUtils::format_time($_GET["timestamp"] * 1 + 600));
        $token->set_full_json(json_encode($this->_receive));
        WeixinTokenCacher::persist($token);
        return true;
    }

    /**
     * 第三方平台 compoment_access_token 是第三方平台的下文中接口的调用凭据，也叫做令牌（component_access_token）。
     * 每个令牌是存在有效期（2小时）的，且令牌的调用不是无限制的，
     * 请第三方平台做好令牌的管理，在令牌快过期时（比如1小时50分）再进行刷新。
     */
    public function getComponentAccessCode()
    {
        //先尝试从缓存读取
        $code = WeixinTokenCacher::getComponentAccessCode();
        if (!empty($code) && $code !== false) {
            Log::debug("从缓存中获取到 component access code: $code");
            return $code;
        }
        $verifyTicket = WeixinTokenCacher::getComponentVerifyTicket();
        if (empty($verifyTicket) || $verifyTicket === false) {
            Log::error("verify ticket is null or expired");
            return false;
        }
        $data = array(
            'component_appid' => $this->component_appid,
            'component_appsecret' => $this->component_appsecret,
            'component_verify_ticket' => $verifyTicket
        );
        $url = self::API_BASE_URL_PREFIX . "/cgi-bin/component/api_component_token";
        $result = $this->http_post($url, self::json_encode($data));
        Log::debug($url);
        Log::debug("result is " . $result);
        if ($result) {
            $json = json_decode($result, true);
            if ($this->checkError($json)) {
                return false;
            }
            $token = new WeixinToken();
            $token->set_parameter_name(WechatClient::COMPONENT_ACCESS_TOKEN);
            $token->set_parameter_value($json["component_access_token"]);
            $token->set_expired_at(TimeUtils::format_time(time() + $json["expires_in"] * 1));
            $token->set_full_json($result);
            WeixinTokenCacher::persist($token);
            return $token->get_parameter_value();
        }
        return false;
    }

    /**
     * 该API用于获取预授权码。预授权码用于公众号授权时的第三方平台方安全验证。
     */
    public function getPreAuthCode()
    {
        $code = WeixinTokenCacher::getPreAuthCode();
        if (!empty($code) && $code !== false) {
            return $code;
        }
        $componentAccessCode = self::getComponentAccessCode();
        if (empty($componentAccessCode) || $componentAccessCode === false) {
            return false;
        }
        $data = array(
            'component_appid' => $this->component_appid
        );
        $url = self::API_BASE_URL_PREFIX . "/cgi-bin/component/api_create_preauthcode?component_access_token=$componentAccessCode";
        $result = $this->http_post($url, self::json_encode($data));
        $this->log($result);
        if ($result) {
            $json = json_decode($result, true);
            if ($this->checkError($json)) {
                return false;
            }
            $token = new WeixinToken();
            $token->set_parameter_name(WechatClient::COMPONENT_PRE_AUTH_CODE);
            $token->set_parameter_value($json["pre_auth_code"]);
            $token->set_expired_at(TimeUtils::format_time(time() + $json["expires_in"]));
            $token->set_full_json($result);
            WeixinTokenCacher::persist($token);
            return $token->get_parameter_value();
        }
        return false;
    }

    /**
     * @param $authorization_code
     * @param $appid
     * @return WeixinToken|bool
     */
    public function getAuthorizerAccessToken($authorization_code, $appid)
    {
        $tokenBean = WeixinTokenCacher::getAuthrizeInfoBean($appid);
        if ($tokenBean !== false) {
            if ($tokenBean->expired()) {
                Log::debug("采用刷新的方式更改 authorizer_access_token");
                $refreshCode = $tokenBean->getParameterFromJson("authorizer_refresh_token");
                return self::refreshAuthorizerAccessToken($refreshCode, $appid);
            }
        }
        $componentAccessCode = self::getComponentAccessCode();
        if (empty($componentAccessCode) || $componentAccessCode === false) {
            return false;
        }
        $data = array(
            'component_appid' => $this->component_appid,
            'authorization_code' => $authorization_code
        );
        $url = self::API_BASE_URL_PREFIX . "/cgi-bin/component/api_query_auth?component_access_token=$componentAccessCode";
        $result = $this->http_post($url, self::json_encode($data));
        Log::debug("获得 微信公众号的 authorizer_access_token");
        Log::debug($result);

        if ($result) {
            $json = json_decode($result, true);
            if ($this->checkError($json)) {
                return false;
            }
            $info = [];
            $authInfo = $json["authorization_info"];
            $info["authorizer_appid"] = $authInfo["authorizer_appid"];
            $info["authorizer_access_token"] = $authInfo["authorizer_access_token"];
            $info["expires_in"] = $authInfo["expires_in"];
            $info["authorizer_refresh_token"] = $authInfo["authorizer_refresh_token"];

            $token = new WeixinToken();
            $token->set_appid($info["authorizer_appid"]);
            $token->set_parameter_name(WechatClient::COMPONENT_AUTHORIZATION_INFO);
            $token->set_parameter_value($authInfo["authorizer_access_token"]);
            $token->set_expired_at(TimeUtils::format_time(time() + $info["expires_in"]));
            $token->set_full_json($result);
            WeixinTokenCacher::persist($token);
            return $token;
        }
        return false;
    }

    public function refreshAuthorizerAccessToken($refreshCode, $appid)
    {
        $componentAccessCode = self::getComponentAccessCode();
        if (empty($componentAccessCode) || $componentAccessCode === false) {
            return false;
        }
        $data = array(
            'component_appid' => $this->component_appid,
            'authorizer_appid' => $refreshCode,
            'authorizer_refresh_token' => $refreshCode
        );
        $url = self::API_BASE_URL_PREFIX . "/cgi-bin/component/api_authorizer_token?component_access_token=$componentAccessCode";
        $result = $this->http_post($url, self::json_encode($data));
        Log::debug("刷新 AuthorizerAccessToken ");
        Log::debug($result);
        if ($result) {
            $json = json_decode($result, true);
            if ($this->checkError($json)) {
                return false;
            }
            $token = new WeixinToken();
            $token->set_appid($appid);
            $token->set_parameter_name(WechatClient::COMPONENT_AUTHORIZATION_INFO);
            $token->set_parameter_value($json["authorizer_access_token"]);
            $token->set_expired_at(TimeUtils::format_time(time() + $json["expires_in"]));
            $token->set_full_json($result);
            WeixinTokenCacher::persist($token);
            return $token->get_parameter_value();
        }
        return false;
    }

    /**
     * 获取授权方的公众号帐号基本信息
     * 该API用于获取授权方的公众号基本信息，包括头像、昵称、帐号类型、认证类型、微信号、原始ID和二维码图片URL。
     * @return WeixinToken|bool
     */
    public function getAppBasicInfo($authAppId)
    {
        $componentAccessCode = self::getComponentAccessCode();
        if (empty($componentAccessCode) || $componentAccessCode === false) {
            return false;
        }
        $data = array(
            'component_appid' => $this->component_appid,
            'authorizer_appid' => $authAppId
        );
        $url = self::API_BASE_URL_PREFIX . "/cgi-bin/component/api_get_authorizer_info?component_access_token=$componentAccessCode";
        $result = $this->http_post($url, self::json_encode($data));
        Log::debug("获取授权方的公众号帐号基本信息");
        Log::debug($result);
        if ($result) {
            $json = json_decode($result, true);
            if ($this->checkError($json)) {
                return false;
            }
            $authInfo = $json["authorizer_info"];
            $token = new WeixinToken();
            $token->set_appid($authAppId);
            $token->set_parameter_name(WechatClient::COMPONENT_AUTHORIZER_INFO);
            $token->set_parameter_value($authInfo["nick_name"]);
            $token->set_expired_at("2099-01-01");
            $token->set_full_json(json_encode($authInfo));
            WeixinTokenCacher::persist($token);
            return $token;
        }
        return false;
    }

    public function configComponents($options)
    {
        $this->component_token = isset($options['component_token']) ? $options['component_token'] : '';
        $this->component_appid = isset($options['component_appid']) ? $options['component_appid'] : '';
        $this->component_appsecret = isset($options['component_appsecret']) ? $options['component_appsecret'] : '';
        $this->component_verify_ticket = isset($options['component_verify_ticket']) ? $options['component_verify_ticket'] : '';
    }

    /**
     * @return string
     */
    public function getComponentAppid()
    {
        return $this->component_appid;
    }

    /**
     * @param string $component_appid
     */
    public function setComponentAppid($component_appid)
    {
        $this->component_appid = $component_appid;
    }

    /**
     * @return string
     */
    public function getComponentAppsecret()
    {
        return $this->component_appsecret;
    }

    /**
     * @param string $component_appsecret
     */
    public function setComponentAppsecret($component_appsecret)
    {
        $this->component_appsecret = $component_appsecret;
    }


}